package com.darkflame.client;

import java.util.ArrayList;
import java.util.logging.Logger;


import com.darkflame.client.interfaces.GenericDebugDisplayer;
import com.darkflame.client.interfaces.SSSGenericFileManager;
import com.darkflame.client.interfaces.GenericProgressMonitor;
import com.darkflame.client.interfaces.GenericPropertyListDisplayer;
import com.darkflame.client.interfaces.GenericWaitFor;
import com.darkflame.client.interfaces.GenericWaitForRepeating;
import com.darkflame.client.semantic.LoadingCallback;
import com.darkflame.client.semantic.RawQueryUtilities;
import com.darkflame.client.semantic.SSSIndex;
import com.darkflame.client.semantic.SSSNode;
import com.darkflame.client.semantic.SSSNodesWithCommonProperty;
import com.darkflame.client.semantic.SSSProperty;
import com.darkflame.client.semantic.SSSTriplet;
import com.darkflame.client.semantic.demo.DemoKnowledgeBase;

/**
 * 
 * SSS is a simple library for using super simple semantic files, or to merely internally
 * have a semantic database for your app.
 * It is based around lists of common properties and supports transitional relationships only.
 *  
 * It is designed to work with *.ntlist files, which in turn reference *.txt files that make up the database you are querying.
 * Nodes can, of course, be added manually in the code too.
 * 
 * https://code.google.com/p/supersimplesemantics/
 * 
 * related project:  https://code.google.com/p/green-fruit-engine/
 *  
 *  @author Thomas Wrobel (thomas@lostagain.nl)
 */
//This code, while fully function, is likely still full of bugs and badly optamised stuff
//For that reason, a safely pig is provided below to help you in times of distress
//
// _._ _..._ .-',     _.._(`))
//'-. `     '  /-._.-'    ',/
//)         \            '.
/// _    _    |             \
//|  a    a    /              |
//\   .-.                     ;  
// '-('' ).-'       ,'       ;
//  '-;           |      .'
//     \           \    /
//     | 7  .__  _.-\   \
//     | |  |  ``/  /`  /
//    /,_|  |   /,_/   /
///,_/      '`-'

public class SuperSimpleSemantics  {

	public static Logger Log = Logger.getLogger("SuperSimpleSemantics");

	
	private final static String baseURI = "examples/DefaultOntologyZ.n3#";
	
	
	static Boolean setupDone = false;	

	/** Determines if to preload the index content **/
	public static boolean preloadIndexs = false;
		
	/** Should we auto-retrieve labels for any nodes loaded? 
	defaults to true **/	
	public static boolean autoloadLabels = true;
	
	
	//-----------------------------------------------------------------
	//The following are interfaces that need to be set for device/OS specific implementatons
	//By the application using the SSS.
	
	public static boolean isAutoloadLabels() {
		return autoloadLabels;
	}




	public static void setAutoloadLabels(boolean autoloadLabels) {
		SuperSimpleSemantics.autoloadLabels = autoloadLabels;
	}




	public static boolean isPreloadIndexs() {
		return preloadIndexs;
	}




	public static void setPreloadIndexs(boolean preloadIndexs) {
		SuperSimpleSemantics.preloadIndexs = preloadIndexs;
	}

	/** the file manager currently in use.
	 * Is used to load files from the filesystem,web, etc**/
	public static SSSGenericFileManager fileManager;

	/** The GenericDebugDisplayer currently in use.
	 * Is used to log semantic progress, if you wish **/
	public static GenericDebugDisplayer debugManager;

	/** the GenericWait currently in use.
	 * As semantic tasks can be time consuming, this allows other functions
	 * to run inbetween.
	 * This is mostly used for interface updates so the software doesn't seem to hang.
	 * The functions in the WaitFor will be triggered quite often during Node lockups and cross-references, as well as index loading **/
	public static GenericWaitFor waitFor = new DefaultWaitFor();
	
	/** Much like "wait for" this is to allow interface or other updates needed 
	 * while the semantic engine is processing.
	 * In this case, its designed for tasks that repeat within the engine.
	 * If your using GWT, you can think of this as a scheduleIncremental **/
	public static GenericWaitForRepeating waitForRep = new DefaultWaitForRepeating();
	
	public static GenericProgressMonitor loadMonitor;
	
	public static GenericProgressMonitor searchMonitor;
	
	
	/** A class to display the currently known property lists **/
	public static GenericPropertyListDisplayer propetyListDisplayer;

	/** if you plan to load everything in at once, and query nodes directly without callbacks, this must be turned on **/
	private static boolean autoRefreshNodeParentCaches=false;
	
	
	/** if autorefresh the cache is on - after loading new files, this will refresh the parent/child relationships of all SSSNodes
	 *  so they can be queried without callbacks **/
	
	public static boolean isAutoRefreshNodeParentCaches() {
		return autoRefreshNodeParentCaches;
	}



	/** if autorefresh the cache is on - after loading new files, this will refresh the parent/child relationships of all SSSNodes
	 *  so they can be queried without callbacks **/
	
	public static void setAutoRefreshNodeParentCaches(
			boolean autoRefreshNodeParentCaches) {
		SuperSimpleSemantics.autoRefreshNodeParentCaches = autoRefreshNodeParentCaches;
	}




	/** adds to the total loading units, if a loading monitor has been supplied **/
	public static void addCPLToDisplayer(SSSNodesWithCommonProperty thisset){
		if (propetyListDisplayer!=null){
			//currently disabled to ensure theres no interface lag from this
		propetyListDisplayer.addCPLToDisplayer(thisset);
			
		}
	}
	
	
	
	
	/** adds to the total loading units, if a loading monitor has been supplied **/
	public static void addToTotalLoadUnits(int i){
		if (loadMonitor!=null){
			loadMonitor.addToTotalProgressUnits(i);
			
		}
	}
	
	/** adds to the total search units, if a loading monitor has been supplied **/
	public static void addToTotalSearchUnits(int i){
		if (searchMonitor!=null){
			searchMonitor.addToTotalProgressUnits(i);
			
		}
	}
	
	/** logs a message if a logger has been supplied **/	
	public static void error(String string){
		if (debugManager!=null){
			debugManager.error(string);
			
		}
	}
	
	/** logs a message if a logger has been supplied **/	
	public static void info(String string){
		if (debugManager!=null){
			debugManager.info(string);
		}
	}
	
	
	/** This should be called before any querys are run **/
		public static void setup() {
			

			RawQueryUtilities.firstTimeSetUp();

			//test some built in properties
			DemoKnowledgeBase.test("oak");
			DemoKnowledgeBase.test("plywood");
	
			//set up callback to automatically parse indexes once loaded
			//in future this will probably be selective indexes as needed - else ram use might
			// get out of control! LoadingCallback
			SSSIndex.setGlobalCallback(new LoadingCallback() {
	
				

				@Override
				public void onFailure(Throwable caught) {
	
					Log.info("no index loaded");
	
				}
	
				@Override
				public void onSuccess(String result) {
					
					Log.info("loaded indexs, now loading SSS Files:");
										
					SSSIndex.parseAllKnownSSSFilesFromIndexs();
					
					
					Log.info("loadeded all SSS Files:");
					Log.info("global sss left = "+SSSNodesWithCommonProperty.getGlobalLeftToLoad());
					
				
					
					
				}
	
			});
			/*
			SSSNodesWithCommonProperty.setGlobalCallback(new Runnable() {
				
				@Override
				public void run() {
					
					
				//	Log.info("_____________loaded "+result);
					
				//	postLoadActions();
					
					/*
					//some extra testing nodes
					final SSSNode green = SSSNode.createSSSNode("green", "green",baseURI);
					final SSSNode red = SSSNode.createSSSNode("red", "red",baseURI);
					final SSSNode color = SSSNode.createSSSNode("color",  "color",baseURI);
					final SSSNode fruit = SSSNode.createSSSNode("fruit",  "fruit",baseURI);
	
					final SSSNode apple = SSSNode.createSSSNode("apple",  "apple",baseURI);
					
					//HashSet<SSSNode>  testresult = QueryEngine.getNodesWithProperty(color, green);
					
					HashSet<SSSNode>  testresult = QueryEngine.getNodesWhichAre(fruit);
					
					//testresult.retainAll(testresult2);
					
					
					Iterator<SSSNode> tri = testresult.iterator();
					while (tri.hasNext()) {
						
						SSSNode sssNode = (SSSNode) tri.next();
						
						Log.info("_____PLabel: "+sssNode.getPURI());
						
					}
					
				}
				
			//	@Override
				//public void onFailure(Throwable caught) {
				//	Log.info("failed to load: "+caught.getMessage());
					
				//}
			});
			
			*/		
			
			
			
			//the below comments are outdated notes, sorry
			
			
			//apples.loadSSSFile("examples/isApple.txt");
			//greenstuff.loadSSSFile("examples/isColor_Green.txt");
			//greenstuff.loadSSSFile("examples/isMore_Green.txt");
			//redstuff.loadSSSFile("examples/isColor_Red.txt");
			//fruits.loadSSSFile("examples/isFruit.txt");
			// get users preferences
	
			// preload all known index files (later can be a sub selection of them
			// if there's too many)
			// ready for query (activate box when complete)
	
			// Set up GUI to allow selection of specific indexs (preferences saved
			// to cookie)
	
			// on query:
			// Parse with hunchamatic to best-guess the request
			// statements are + by default - for things to exclude
			// Spaces are interpreted as "AND"
	
			// Figure out the URIs they most likely are referring too and list them
			// so the user can check
			//
			// get all propertys asked for (either to include or exclude) ie green
	
			// look over indexs for lists of things with this class (ie, all types
			// of green)
	
			// store in node file both the name and all known subtypes and
			// equivalents
	
			// iterate fill up the new node subtypes untill no new ones are found
	
			// now retrieve the triplets from the index file.
			// ie. all the stuff that is any of the types or subtypes of that above
			// (all green things, all fruit things etc)
	
			// once all triplets are retrieved and filled we process the query with
			// this new knowledge base
	
			// start with the inner most bracket, simply cross referencing nodes to
			// include/exclude
			// +isGreen +isFruit
			// add the results together from any ORs
			// iterate to next bracket set utill we reach the end
	
			// process results into node list
			// load equilivents as expansions in a expandable widget
			// as well as the domains each result was deduced from.
	
			// ===============
	
			// class's needed:
			// node file (stores label,uri,equilivents and subtypes)
			// triplet property list (stores all nodes with the same property)
	
			// result file (stores a node and the uri's the result was deduced from)
			setupDone=true;
		}
/**  Loads the index **/
		public static void loadIndexAt(String trustedIndex)
		{
			ArrayList<String> indexs = new ArrayList<String>();
			indexs.add(trustedIndex);
			SSSIndex.loadIndexsAt(indexs);
			return;
		}


	/** logs a message if a logger has been supplied **/
	public static void log(String string){
		if (debugManager!=null){
			debugManager.log(string);
			
		}
	}
	
	/** sets what the loading is currently doing **/
	public static void setCurrentLoadProcess(String message){
		if (loadMonitor!=null){
			loadMonitor.setCurrentProcess(message);
			
		}
	}
	
	/** clears the current indexes and nodes **/
	public static void clearAllIndexsAndNodes() {
		
		//clear existing indexes
		SSSIndex.clearAllIndexs();
		SSSIndex.clearLoadingList();
		
		SSSNodesWithCommonProperty.clearAll();
			
		SSSNode.clearAllKnowenNodes();
		SSSTriplet.clearKnownTriplets();
		SSSProperty.clearAllSSSPropertys();
	}
	
	
	/** loads the specified indexes.
	 * It uses the specified filemanager called with the strings specified as location **/
	public static void loadIndexsAt(ArrayList<String> trustedIndexs) {

		SuperSimpleSemantics.setCurrentLoadProcess("Loading trusted indexs");
		
		SSSIndex.loadIndexsAt(trustedIndexs);
		
	}
	
	/** sets what the search is currently doing **/
	public static void setCurrentSearchProcess(String message){
		if (searchMonitor!=null){
			searchMonitor.setCurrentProcess(message);
			
		}
	}
	
	/** set the GenericDebugDisplayer currently in use.
	 * Is used for log semantic progress, if you wish **/
	public static void setDebugBox(GenericDebugDisplayer debuger) {
		debugManager = debuger;
		
		SSSNodesWithCommonProperty.setDebugPanel(debugManager);
		SSSIndex.setDebugPanel(debugManager);
		
	}

	/** Set the file manager to use.
	 * This is used to load files from the filesystem,web, etc**/
	public static void setFileManager(SSSGenericFileManager filemanager) {
		fileManager = filemanager;
	}
	

	
	public static void setGenericLoadingMonitor(GenericProgressMonitor loadicon) {
		loadMonitor = loadicon;
	}
	
	/** allows you to set a class to display the currently known property lists, if you wish **/
	public static void setGenericPropertyListDisplayer(GenericPropertyListDisplayer PLdis) {
		propetyListDisplayer = PLdis;
		
		propetyListDisplayer.setCPLDatabase(SSSNodesWithCommonProperty.globalNodesWithPropertyListByPredicate);
		
	}

	public static void setGenericSearchMonitor(GenericProgressMonitor searchmonitor) {
		searchMonitor = searchmonitor;
	}
	
	/** set the GenericWait currently in use.
	 * As semantic tasks can be time consuming, this allows other functions
	 * to run inbetween.
	 * This is mostly used for interface updates so the software doesn't seem to hang.
	 * The functions in the WaitFor will be triggered quite often during Node lockups and cross-references, as well as index loading **/

	public static void setGenericWaitFor(GenericWaitFor waitfor) {
		waitFor = waitfor;
	}
	
	/** Much like "wait for" this is to allow interface or other updates needed 
	 * while the semantic engine is processing.
	 * In this case, its designed for tasks that repeat within the engine.
	 * If your using GWT, you can think of this as a scheduleIncremental **/
	public static void setGenericWaitForRepeating(GenericWaitForRepeating waitforrep) {
		waitForRep = waitforrep;
	}
	
	/** Sets functions to run when finished loading.
	 * This only fires once. If you want it to fire when more indexs or CPLs are loaded, you will need
	 * to set it again. **/
	static public void setLoadedRunnable(Runnable runWhenDone){
		
		if (!setupDone){
			Log.info("WARNING: .setup() not run yet, post-load Runnable will never fire!");
		}
		
		SSSNodesWithCommonProperty.setGlobalCallback(runWhenDone);
				
	}
	
	
	
	/** steps the loading monitor forward **/
	public static void stepLoadClockForward(){
		if (loadMonitor!=null){
			loadMonitor.stepProgressForward();
			
		}
	}
	
	/** steps the search monitor forward **/
	public static void stepSearchClockForward(){
		if (searchMonitor!=null){
			searchMonitor.stepProgressForward();
			
		}
	}
	/** set the search monitors current progress **/
	public static void setSearchClockProgress(int i){
		if (searchMonitor!=null){
			searchMonitor.setCurrentProgress(i);
			
		}
	}
	
	/** set the search monitors current progress **/
	public static void setSearchClockTotal(int i){
		if (searchMonitor!=null){
			searchMonitor.setTotalProgressUnits(i);
			
		}
	}




	public static void log(String message, String color) {
		if (debugManager!=null){
			debugManager.log(message,color);
			
		}
		
	}




	public static String getDefaultBaseURI() {
		
		return baseURI;
	}
	
}
